package com.neusoft.hifly.security;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;

/**
 * AES安全编码组件
 * <p>
 * AES已经变成目前对称加密中最流行算法之一；AES可以使用128、192、和256位密钥，并且用128位分组加密和解密数据。
 */
public final class AESCoder {

	/**
	 * ALGORITHM 算法 <br>
	 * 可替换为以下任意一种算法，同时key值的size相应改变。
	 *
	 * <pre>
	 * AES          		key size must be equal to 128, 192 or 256,but 192 and 256 bits may not be available
	 * </pre>
	 */
	private static final String ALGORITHM = "AES";
	/**
	 * 密钥长度
	 */
	private static final int KEYSIZE = 128;

	/**
	 * 加密
	 *
	 * @param content
	 *            需要加密的内容
	 * @param password
	 *            加密密码
	 * @param encode
	 *            字符集
	 * @return 密码
	 */
	public static String encrypt(final String content, final String password, final String encode) {
		try {
			final KeyGenerator kgen = KeyGenerator.getInstance(AESCoder.ALGORITHM);
			kgen.init(AESCoder.KEYSIZE, new SecureRandom(password.getBytes()));
			final SecretKey secretKey = kgen.generateKey();
			final byte[] enCodeFormat = secretKey.getEncoded();
			final SecretKeySpec key = new SecretKeySpec(enCodeFormat, AESCoder.ALGORITHM);
			final Cipher cipher = Cipher.getInstance(AESCoder.ALGORITHM); // 创建密码器
			final byte[] byteContent = content.getBytes(encode);
			cipher.init(Cipher.ENCRYPT_MODE, key); // 初始化
			final byte[] result = cipher.doFinal(byteContent);
			return AESCoder.parseByte2HexStr(result); // 加密
		} catch (final NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (final NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (final InvalidKeyException e) {
			e.printStackTrace();
		} catch (final UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (final IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (final BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 加密
	 *
	 * @param content
	 *            需要加密的内容
	 * @param password
	 *            加密密码
	 * @return 密码
	 */
	public static String encrypt(final String content, final String password) {
		try {
			final KeyGenerator kgen = KeyGenerator.getInstance(AESCoder.ALGORITHM);
			//WuGang 2013-12-25 解决Linux服务器下每次生成随机码不同问题
			final SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
			secureRandom.setSeed(password.getBytes());
			kgen.init(AESCoder.KEYSIZE, secureRandom);
			final SecretKey secretKey = kgen.generateKey();
			final byte[] enCodeFormat = secretKey.getEncoded();
			final SecretKeySpec key = new SecretKeySpec(enCodeFormat, AESCoder.ALGORITHM);
			final Cipher cipher = Cipher.getInstance(AESCoder.ALGORITHM); // 创建密码器
			final byte[] byteContent = content.getBytes();
			cipher.init(Cipher.ENCRYPT_MODE, key); // 初始化
			final byte[] result = cipher.doFinal(byteContent);
			return AESCoder.parseByte2HexStr(result); // 加密
		} catch (final NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (final NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (final InvalidKeyException e) {
			e.printStackTrace();
		} catch (final IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (final BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 解密
	 *
	 * @param content
	 *            待解密内容
	 * @param password
	 *            解密密钥
	 * @return 原码
	 */
	public static String decrypt(final String content, final String password) {
		try {
			final KeyGenerator kgen = KeyGenerator.getInstance(AESCoder.ALGORITHM);
			//WuGang 2013-12-25 解决Linux服务器下每次生成随机码不同问题
			final SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
			secureRandom.setSeed(password.getBytes());
			kgen.init(AESCoder.KEYSIZE, secureRandom);
			//kgen.init(AESCoder.KEYSIZE, new SecureRandom(password.getBytes()));
			final SecretKey secretKey = kgen.generateKey();
			final byte[] enCodeFormat = secretKey.getEncoded();
			final SecretKeySpec key = new SecretKeySpec(enCodeFormat, AESCoder.ALGORITHM);
			final Cipher cipher = Cipher.getInstance(AESCoder.ALGORITHM); // 创建密码器
			cipher.init(Cipher.DECRYPT_MODE, key); // 初始化
			final byte[] result = cipher.doFinal(AESCoder.parseHexStr2Byte(content));
			return new String(result); // 加密
		} catch (final NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (final NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (final InvalidKeyException e) {
			e.printStackTrace();
		} catch (final IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (final BadPaddingException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 生成密钥
	 *
	 * @return
	 * @throws Exception
	 */
	public static String initKey() {
		return DESCoder.initKey(null);
	}

	/**
	 * 生成密钥
	 *
	 * @param seed
	 * @return
	 * @throws Exception
	 */
	public static String initKey(final String seed) {
		try {
			SecureRandom secureRandom = null;
			if (seed != null) {
				// 每次生成的密钥都一样
				secureRandom = new SecureRandom(Base64.decodeBase64(seed.getBytes()));
			} else {
				secureRandom = new SecureRandom();
			}
			final KeyGenerator kg = KeyGenerator.getInstance(AESCoder.ALGORITHM);
			kg.init(AESCoder.KEYSIZE, secureRandom);
			final SecretKey secretKey = kg.generateKey();
			return new String(Base64.encodeBase64(secretKey.getEncoded()));
		} catch (final NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 将二进制转换成16进制
	 *
	 * @param buf
	 * @return String
	 */
	private static String parseByte2HexStr(final byte buf[]) {
		final StringBuffer sb = new StringBuffer();
		for (final byte element : buf) {
			String hex = Integer.toHexString(element & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			sb.append(hex.toUpperCase());
		}
		return sb.toString();
	}

	/**
	 * 将16进制转换为二进制
	 *
	 * @param hexStr
	 * @return byte[]
	 */
	private static byte[] parseHexStr2Byte(final String hexStr) {
		if (hexStr.length() < 1) {
			return null;
		}
		final byte[] result = new byte[hexStr.length() / 2];
		for (int i = 0; i < hexStr.length() / 2; i++) {
			final int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
			final int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
			result[i] = (byte) (high * 16 + low);
		}
		return result;
	}

	/**
	 * 测试
	 *
	 * @param args
	 *            参数
	 * @throws Exception
	 *             异常
	 */
	public static void main(final String[] args) {
		// 密钥
		final String key = "12345678";
		System.out.println("密钥：" + key);
		// 待加密的内容
		final String content = "Hellow Word!This is a organ key.斯蒂芬圣诞圣诞圣诞";
		// 字符集
		final String encode = "UTF-8";
		//加密
		System.out.println("加密前：" + content);
		final String encryptResultStr = AESCoder.encrypt(content, key, encode);
		System.out.println("加密后：" + encryptResultStr);
		//解密
		System.out.println("解密后：" + AESCoder.decrypt(encryptResultStr, key));
	}
}
